package com.yc.testupload.crawler.strategy;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import com.yc.testupload.crawler.test.Question;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;

import io.github.bonigarcia.wdm.WebDriverManager;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 使用Selenium WebDriver的爬虫策略
 * 适用于需要JavaScript渲染的动态网页
 */
public class SeleniumCrawlingStrategy implements CrawlingStrategy {
    private static final Logger logger = LogManager.getLogger(SeleniumCrawlingStrategy.class);
    
    // 最大等待时间（秒）
    private static final int MAX_WAIT_SECONDS = 30;
    // 最大题目数量限制
    private static final int MAX_QUESTIONS = 30;

    @Override
    public boolean isApplicable(String url) {
        // 这个策略可以作为备选策略，适用于需要JavaScript渲染的网页
        // 也可以根据URL特征判断是否优先使用Selenium
        return true;
    }
    
    @Override
    public String extractQuestions(String html) {
        // 注意：当直接传入HTML内容时，Selenium策略可能不是最佳选择
        // 这里我们可以使用JSoup解析HTML，然后转换为字符串格式返回
        logger.warn("Selenium策略收到HTML内容，而不是URL。使用JSoup进行基本解析。");
        List<Question> questions = extractQuestionsWithJsoup(html);
        return convertQuestionsToString(questions);
    }
    
    /**
     * 使用Selenium WebDriver从URL抓取并提取面试题
     * @param url 要抓取的URL
     * @return 提取的面试题文本
     */
    public String extractQuestionsFromUrl(String url) {
        logger.info("开始使用Selenium策略从URL提取面试题: {}", url);
        WebDriver driver = null;
        List<Question> questions = new ArrayList<>();
        
        try {
            // 自动下载和设置ChromeDriver
            WebDriverManager.chromedriver().setup();
            
            // 配置Chrome选项
            ChromeOptions options = new ChromeOptions();
            options.addArguments("--headless"); // 无头模式，不显示浏览器窗口
            options.addArguments("--disable-gpu");
            options.addArguments("--window-size=1920,1080");
            options.addArguments("--no-sandbox");
            options.addArguments("--disable-dev-shm-usage");
            options.addArguments("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
            
            // 初始化WebDriver
            driver = new ChromeDriver(options);
            driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(MAX_WAIT_SECONDS));
            
            // 访问URL
            logger.info("正在访问URL: {}", url);
            driver.get(url);
            
            // 等待页面加载完成
            WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(MAX_WAIT_SECONDS));
            wait.until(ExpectedConditions.jsReturnsValue("return document.readyState === 'complete';"));
            
            // 等待一些动态内容加载
            Thread.sleep(3000);
            
            // 获取完整渲染后的页面源码
            String pageSource = driver.getPageSource();
            logger.info("成功获取页面源码，长度: {}字符", pageSource.length());
            
            // 使用JSoup解析提取的页面源码
            List<Question> extractedQuestions = extractQuestionsWithJsoup(pageSource);
            questions.addAll(extractedQuestions);
            logger.info("已提取 {} 道面试题", extractedQuestions.size());
            
            // 如果没有提取到结构化题目，返回页面主要内容
            if (extractedQuestions.isEmpty()) {
                logger.warn("未能使用Selenium策略提取到任何面试题");
                // 这里我们暂时不添加额外内容，让convertQuestionsToString处理空列表情况
            }
            
        } catch (Exception e) {
            logger.error("使用Selenium提取面试题时发生异常", e);
            return "使用Selenium提取面试题失败: " + e.getMessage();
        } finally {
            // 确保关闭WebDriver
            if (driver != null) {
                try {
                    driver.quit();
                    logger.info("WebDriver已关闭");
                } catch (Exception e) {
                    logger.error("关闭WebDriver时发生异常", e);
                }
            }
        }
        
        return convertQuestionsToString(questions);
    }
    
    /**
     * 将Question对象列表转换为字符串格式
     */
    private String convertQuestionsToString(List<Question> questions) {
        StringBuilder result = new StringBuilder();
        
        for (Question q : questions) {
            result.append("题目 ").append(q.getNumber()).append(": ").append(q.getContent()).append("\n");
            if (q.getAnswer() != null && !q.getAnswer().isEmpty()) {
                result.append("答案: ").append(q.getAnswer()).append("\n\n");
            } else {
                result.append("\n");
            }
        }
        
        return result.toString();
    }
    
    @Override
    public String extractTitle(String html) {
        String title = "";
        try {
            Document doc = Jsoup.parse(html);
            Element titleElement = doc.selectFirst("title");
            if (titleElement != null) {
                title = titleElement.text().trim();
            }
        } catch (Exception e) {
            logger.error("提取标题时发生异常", e);
        }
        return title.isEmpty() ? "未命名页面" : title;
    }
    
    /**
     * 使用JSoup解析HTML内容，提取面试题
     * @param html HTML内容
     * @return 提取的Question对象列表
     */
    private List<Question> extractQuestionsWithJsoup(String html) {
        List<Question> questions = new ArrayList<>();
        
        try {
            Document doc = Jsoup.parse(html);
            
            // 尝试提取常见的题目格式
            // 1. 查找包含"题目"、"问题"等关键词的元素
            Elements questionElements = doc.select(":containsOwn(题目), :containsOwn(问题), .question, .topic");
            
            for (Element element : questionElements) {
                if (questions.size() >= MAX_QUESTIONS) break;
                
                Question question = new Question();
                
                // 提取题目编号
                String text = element.text();
                Matcher numberMatcher = Pattern.compile("(\\d+)[、.]").matcher(text);
                if (numberMatcher.find()) {
                    question.setNumber(numberMatcher.group(1));
                } else {
                    question.setNumber(String.valueOf(questions.size() + 1));
                }
                
                // 提取题目内容
                question.setContent(text);
                
                // 尝试查找答案
                Element nextElement = element.nextElementSibling();
                if (nextElement != null) {
                    String nextText = nextElement.text();
                    if (nextText.contains("答案") || nextText.contains("解析") || nextText.contains("解答")) {
                        question.setAnswer(nextText);
                    }
                }
                
                questions.add(question);
            }
            
            // 如果没有找到题目，尝试其他方式提取
            if (questions.isEmpty()) {
                logger.info("未找到明确的题目元素，尝试提取段落内容");
                extractQuestionsFromParagraphs(doc, questions);
            }
            
        } catch (Exception e) {
            logger.error("使用JSoup提取面试题时发生异常", e);
        }
        
        return questions;
    }
    
    /**
     * 从段落中提取题目
     */
    private void extractQuestionsFromParagraphs(Document doc, List<Question> questions) {
        Elements paragraphs = doc.select("p, div, article");
        StringBuilder currentQuestion = new StringBuilder();
        StringBuilder currentAnswer = new StringBuilder();
        boolean isAnswerSection = false;
        
        for (Element paragraph : paragraphs) {
            if (questions.size() >= MAX_QUESTIONS) break;
            
            String text = paragraph.text().trim();
            if (text.isEmpty() || text.length() < 10) continue;
            
            // 检查是否是新题目的开始
            if (text.matches("^(\\d+[、.]|第.*题)")) {
                // 保存之前的题目（如果有）
                if (currentQuestion.length() > 0) {
                    Question q = new Question();
                    q.setNumber(String.valueOf(questions.size() + 1));
                    q.setContent(currentQuestion.toString().trim());
                    if (currentAnswer.length() > 0) {
                        q.setAnswer(currentAnswer.toString().trim());
                    }
                    questions.add(q);
                    currentQuestion.setLength(0);
                    currentAnswer.setLength(0);
                    isAnswerSection = false;
                }
                
                currentQuestion.append(text).append("\n");
            } 
            // 检查是否是答案部分
            else if (text.contains("答案") || text.contains("解析") || text.contains("解答")) {
                isAnswerSection = true;
                currentAnswer.append(text).append("\n");
            } 
            // 添加到当前题目或答案
            else if (currentQuestion.length() > 0) {
                if (isAnswerSection) {
                    currentAnswer.append(text).append("\n");
                } else {
                    currentQuestion.append(text).append("\n");
                }
            }
        }
        
        // 保存最后一个题目
        if (currentQuestion.length() > 0) {
            Question q = new Question();
            q.setNumber(String.valueOf(questions.size() + 1));
            q.setContent(currentQuestion.toString().trim());
            if (currentAnswer.length() > 0) {
                q.setAnswer(currentAnswer.toString().trim());
            }
            questions.add(q);
        }
    }
    
    /**
     * 从WebDriver提取页面主要内容
     * @param driver WebDriver实例
     * @return 页面主要内容
     */
    private String extractMainContent(WebDriver driver) {
        StringBuilder content = new StringBuilder();
        
        try {
            // 尝试提取常见的内容区域
            List<String> contentSelectors = new ArrayList<>();
            contentSelectors.add("#content");
            contentSelectors.add(".content");
            contentSelectors.add("main");
            contentSelectors.add("article");
            
            for (String selector : contentSelectors) {
                try {
                    WebElement element = driver.findElement(By.cssSelector(selector));
                    if (element != null) {
                        content.append(element.getText());
                        break;
                    }
                } catch (Exception e) {
                    // 选择器不存在，继续尝试下一个
                    continue;
                }
            }
            
            // 如果没有找到特定的内容区域，返回body文本
            if (content.length() == 0) {
                WebElement body = driver.findElement(By.tagName("body"));
                content.append(body.getText());
            }
            
        } catch (Exception e) {
            logger.error("提取页面主要内容时出错", e);
            content.append("提取页面内容失败: ").append(e.getMessage());
        }
        
        return content.toString();
    }
    
    /**
     * 从URL提取页面标题
     * @param url 页面URL
     * @return 页面标题
     */
    public String extractTitleFromUrl(String url) {
        WebDriver driver = null;
        String title = "未命名页面";
        
        try {
            // 自动下载和设置ChromeDriver
            WebDriverManager.chromedriver().setup();
            
            // 配置Chrome选项
            ChromeOptions options = new ChromeOptions();
            options.addArguments("--headless");
            options.addArguments("--disable-gpu");
            
            // 初始化WebDriver
            driver = new ChromeDriver(options);
            
            // 访问URL
            driver.get(url);
            
            // 获取页面标题
            title = driver.getTitle();
            logger.info("成功从URL提取标题: {}", title);
            
        } catch (Exception e) {
            logger.error("使用Selenium提取页面标题时出错", e);
        } finally {
            // 关闭浏览器
            if (driver != null) {
                try {
                    driver.quit();
                } catch (Exception e) {
                    logger.error("关闭Selenium WebDriver时出错", e);
                }
            }
        }
        
        return title;
    }
}